#include "../source/Server.hpp"
#include "Http.hpp"

// 字符串分割函数 - 返回结果个数
static size_t StrSplit(const std::string &src, const std::string sep, std::vector<std::string> *array)
{
    int offset = 0;
    while (offset < src.size())
    {
        auto pos = src.find(sep, offset);
        if (pos == std::string::npos)
        {
            // 说明找到文件末尾还没找到
            // abc,bcd - 我们还要把最后一段处理了
            array->push_back(src.substr(offset));
            return array->size();
        }
        if (pos != offset)
        {
            array->push_back(src.substr(offset, pos - offset));
        }
        offset = pos + sep.size();
    }
    return array->size();
}

// 读取文件内容
static bool ReadFile(const std::string &filename, std::string *buffer)
{
    std::ifstream in(filename.c_str(), std::ios::binary);
    if (!in.is_open())
    {
        ERR_LOG("filename: %s not found!!", filename.c_str());
        return false;
    }
    int fullsize = 0;
    in.seekg(0, in.end);
    fullsize = in.tellg(); // 获取文件的总大小。
    in.seekg(0, in.beg);   // 回到初始的位置
    buffer->resize(fullsize);
    in.read(&((*buffer)[0]), fullsize);
    if (in.good() == false)
    {
        ERR_LOG("filename: %s read error!!!", filename.c_str());
        return false;
    }
    return true;
}

static bool WriteFile(const std::string &filename, const std::string &buffer)
{
    // std::ios::trunc: 保证每一次文件的内容都是重新写的
    std::ofstream out(filename.c_str(), std::ios::binary | std::ios::trunc);
    if (!out.is_open())
    {
        ERR_LOG("filename: %s not found!!", filename.c_str());
        return false;
    }
    out.write(buffer.c_str(), buffer.size());
    if (out.good() == false)
    {
        ERR_LOG("filename: %s write error!!!", filename.c_str());
        return false;
    }
    return true;
}
static std::string UrlEncode(const std::string &url, bool space_convert_2_plus = false)
{
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '.' || url[i] == '-' || url[i] == '_' || url[i] == '~' || isalnum(url[i]))
        {
            res += url[i];
            continue;
        }
        if (url[i] == ' ' && space_convert_2_plus)
        {
            res += '+';
            continue;
        }
        char tmp[4] = {0};
        snprintf(tmp, 4, "%%%02X", url[i]);
        res += tmp;
    }
    return res;
}
static int Char2Int(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    else if (c >= 'a' && c <= 'z')
        return c - 'a' + 10;
    else if (c >= 'A' && c <= 'Z')
        return c - 'A' + 10;
    else
        return -1;
}
static std::string UrlDecode(const std::string &url, bool plus_convert_2_space = false)
{
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '%' && (i + 2) < url.size())
        {
            int v1 = Char2Int(url[i + 1]);
            int v2 = Char2Int(url[i + 2]);
            char c = v1 * 16 + v2;
            res += c;
            //%2B, i+=2，然后再次循环i+1，总共是i+3，刚好是下一个字符
            i += 2;
            continue;
        }

        if (url[i] == '+' && plus_convert_2_space)
        {
            res += ' ';
            continue;
        }
        res += url[i];
    }
    return res;
}
  static std::string Statu2Desc(int status)
    {
        std::unordered_map<int, std::string> _status =
            {
                {100, "Continue"},
                {101, "Switching Protocol"},
                {102, "Processing"},
                {103, "Early Hints"},
                {200, "OK"},
                {201, "Created"},
                {202, "Accepted"},
                {203, "Non-Authoritative Information"},
                {204, "No Content"},
                {205, "Reset Content"},
                {206, "Partial Content"},
                {207, "Multi-Status"},
                {208, "Already Reported"},
                {226, "IM Used"},
                {300, "Multiple Choice"},
                {301, "Moved Permanently"},
                {302, "Found"},
                {303, "See Other"},
                {304, "Not Modified"},
                {305, "Use Proxy"},
                {306, "unused"},
                {307, "Temporary Redirect"},
                {308, "Permanent Redirect"},
                {400, "Bad Request"},
                {401, "Unauthorized"},
                {402, "Payment Required"},
                {403, "Forbidden"},
                {404, "Not Found"},
                {405, "Method Not Allowed"},
                {406, "Not Acceptable"},
                {407, "Proxy Authentication Required"},
                {408, "Request Timeout"},
                {409, "Conflict"},
                {410, "Gone"},
                {411, "Length Required"},
                {412, "Precondition Failed"},
                {413, "Payload Too Large"},
                {414, "URI Too Long"},
                {415, "Unsupported Media Type"},
                {416, "Range Not Satisfiable"},
                {417, "Expectation Failed"},
                {418, "I'm a teapot"},
                {421, "Misdirected Request"},
                {422, "Unprocessable Entity"},
                {423, "Locked"},
                {424, "Failed Dependency"},
                {425, "Too Early"},
                {426, "Upgrade Required"},
                {428, "Precondition Required"},
                {429, "Too Many Requests"},
                {431, "Request Header Fields Too Large"},
                {451, "Unavailable For Legal Reasons"},
                {501, "Not Implemented"},
                {502, "Bad Gateway"},
                {503, "Service Unavailable"},
                {504, "Gateway Timeout"},
                {505, "HTTP Version Not Supported"},
                {506, "Variant Also Negotiates"},
                {507, "Insufficient Storage"},
                {508, "Loop Detected"},
                {510, "Not Extended"},
                {511, "Network Authentication Required"}};
        auto it = _status.find(status);
        if (it == _status.end())
        {
            return "UnKnown";
        }
        return it->second;
    }
    // 文件后缀 -> http的文件类型
    static std::string ExtMime(std::string ext)
    {
        std::unordered_map<std::string, std::string> _ext =
            {
                {".aac", "audio/aac"},
                {".abw", "application/x-abiword"},
                {".arc", "application/x-freearc"},
                {".avi", "video/x-msvideo"},
                {".azw", "application/vnd.amazon.ebook"},
                {".bin", "application/octet-stream"},
                {".bmp", "image/bmp"},
                {".bz", "application/x-bzip"},
                {".bz2", "application/x-bzip2"},
                {".csh", "application/x-csh"},
                {".css", "text/css"},
                {".csv", "text/csv"},
                {".doc", "application/msword"},
                {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
                {".eot", "application/vnd.ms-fontobject"},
                {".epub", "application/epub+zip"},
                {".gif", "image/gif"},
                {".htm", "text/html"},
                {".html", "text/html"},
                {".ico", "image/vnd.microsoft.icon"},
                {".ics", "text/calendar"},
                {".jar", "application/java-archive"},
                {".jpeg", "image/jpeg"},
                {".jpg", "image/jpeg"},
                {".js", "text/javascript"},
                {".json", "application/json"},
                {".jsonld", "application/ld+json"},
                {".mid", "audio/midi"},
                {".midi", "audio/x-midi"},
                {".mjs", "text/javascript"},
                {".mp3", "audio/mpeg"},
                {".mpeg", "video/mpeg"},
                {".mpkg", "application/vnd.apple.installer+xml"},
                {".odp", "application/vnd.oasis.opendocument.presentation"},
                {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
                {".odt", "application/vnd.oasis.opendocument.text"},
                {".oga", "audio/ogg"},
                {".ogv", "video/ogg"},
                {".ogx", "application/ogg"},
                {".otf", "font/otf"},
                {".png", "image/png"},
                {".pdf", "application/pdf"},
                {".ppt", "application/vnd.ms-powerpoint"},
                {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
                {".rar", "application/x-rar-compressed"},
                {".rtf", "application/rtf"},
                {".sh", "application/x-sh"},
                {".svg", "image/svg+xml"},
                {".swf", "application/x-shockwave-flash"},
                {".tar", "application/x-tar"},
                {".tif", "image/tiff"},
                {".tiff", "image/tiff"},
                {".ttf", "font/ttf"},
                {".txt", "text/plain"},
                {".vsd", "application/vnd.visio"},
                {".wav", "audio/wav"},
                {".weba", "audio/webm"},
                {".webm", "video/webm"},
                {".webp", "image/webp"},
                {".woff", "font/woff"},
                {".woff2", "font/woff2"},
                {".xhtml", "application/xhtml+xml"},
                {".xls", "application/vnd.ms-excel"},
                {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
                {".xml", "application/xml"},
                {".xul", "application/vnd.mozilla.xul+xml"},
                {".zip", "application/zip"},
                {".3gp", "video/3gpp"},
                {".3g2", "video/3gpp2"},
                {".7z", "application/x-7z-compressed"}};
        auto it = _ext.find(ext);
        if (it == _ext.end())
        {
            return "application/octet-stream";
        }
        return it->second;                
    }
    // 是否是一个目录
    static bool IsDirectory(const std::string& filename){
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if (ret < 0){
            ERR_LOG("STAT FAIL!!");
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    // 是否是一个普通文件
    static bool IsRegular(const std::string& filename){
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if (ret < 0){
            ERR_LOG("STAT FAIL!!");
            return false;
        }
        return S_ISREG(st.st_mode);
    }    
    static bool IsRegularPath(const std::string url){   
        std::vector<std::string> array;
        StrSplit(url,"/",&array);
        int level = 0;
        for (auto& x : array){
            if (x == ".."){
                if (--level < 0) return false;             
                continue;   
            }
            ++level;
        }
        return true;
    }    
int main()
{
    char* a = "12345\n";
    std::cout << (&a[6] - &a[0]) << std::endl;
    // std::string url = "/http/source.txt";
    // std::cout << IsRegular(url) << std::endl;
    // std::cout << IsDirectory("testDir/") << std::endl;
    // std::cout << IsDirectory("ttttt.c") << std::endl;
    // std::cout << IsRegular("ttttt.c") << std::endl;
    // std::cout << IsRegular("testDir/") << std::endl;
    // std::cout << Statu2Desc(200) << std::endl;
    // std::cout << Statu2Desc(2000000000) << std::endl;
    // std::cout << ExtMime(".html") << std::endl;
    // std::cout << ExtMime(".htmlasdasdasd") << std::endl;

    // std::string url = "C  C";
    // std::string res = UrlEncode(url, true);
    // std::cout << res << std::endl;
    // std::string tmp = UrlDecode(res,true);
    // std::cout << tmp << std::endl;
    
        // std::string s = "abc,,,,,,,,,bde";
        // std::vector<std::string> array;
        // StrSplit(s,",",&array);
        // for (auto& x : array){
        //     std::cout << "[" << x << "]\n";
        // }
        // std::string buff;
        // ReadFile("../test/timer.cpp",&buff);
        // // std::cout << buff << std::endl;
        // WriteFile("ttttt.c",buff);
        return 0;
}